﻿' Copyright (c) Microsoft Open Technologies, Inc.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

Imports System.IO
Imports System.Console

''' <summary>
''' Contains the startup code, command line argument processing, and driving the execution of the tool.
''' </summary>
Module Program

    Function Main(args As String()) As Integer

        Const exitWithErrors = 1,
              exitWithoutErrors = 0

        Try

            Dim paths = From arg In args Where Not arg.StartsWith("/")

            Dim switches = From arg In args Where arg.StartsWith("/")

            ' Write usage.
            If switches.Contains("/?") OrElse paths.Count <> 2 OrElse switches.Count > 2 Then
                WriteLine("VBSyntaxGenerator.exe input output [/source] [/test]")
                WriteLine()
                WriteLine("  /source        Generates syntax model source code.")
                WriteLine("                 This is the default. May be used to modify /test.")
                WriteLine("  /test          Generates syntax model unit tests.")
                WriteLine("                 Suppreses generation of syntax model source code by default.")

                Return exitWithErrors
            End If

            Dim inputFile = paths(0)
            Dim outputFile = paths(1)
            Dim writeTests = switches.Contains("/test", StringComparer.OrdinalIgnoreCase)
            Dim writeSource = Not writeTests OrElse switches.Contains("/source", StringComparer.OrdinalIgnoreCase)
            Dim writeUsage = switches.Contains("/?")

            If Not File.Exists(inputFile) Then
                WriteLine("Input file not found - ""{0}""", inputFile)

                Return exitWithErrors
            End If

            Dim definition = ReadDefinition(inputFile)

            WriteOutput(outputFile, definition, writeSource, writeTests)

            Return exitWithoutErrors
        Catch ex As Exception
            WriteLine("FATAL ERROR: {0}", ex.Message)
            WriteLine(ex.StackTrace)

            Return exitWithErrors
        End Try

    End Function

    Function ReadDefinition(inputFile As String) As ParseTree
        Dim definition = ReadTheTree(inputFile)

        ValidateTree(definition)

        Return definition
    End Function

    Sub WriteOutput(outputFile As String, definition As ParseTree, writeSource As Boolean, writeTests As Boolean)

        Using output As New StreamWriter(outputFile)
            output.WriteLine("' Definition of syntax model.")
            output.WriteLine("' Generated by a tool on {0:g}", Date.Now)
            output.WriteLine("' DO NOT HAND EDIT")
            output.WriteLine()

            output.WriteLine("Imports System.Collections.Generic")
            output.WriteLine("Imports System.Collections.Immutable")
            output.WriteLine("Imports System.Runtime.CompilerServices")
            output.WriteLine("Imports Microsoft.CodeAnalysis.VisualBasic.Syntax")
            output.WriteLine("Imports Roslyn.Utilities")

            If writeTests Then
                output.WriteLine("Imports Xunit")
            End If

            If writeSource Then

                Dim redNodeWriter As New redNodeWriter(definition)
                redNodeWriter.WriteTreeAsCode(output)

                Dim greenNodeWriter As New greenNodeWriter(definition)
                greenNodeWriter.WriteTreeAsCode(output)

                Dim redFactoryWriter As New RedNodeFactoryWriter(definition)
                redFactoryWriter.WriteFactories(output)

                Dim greenFactoryWriter As New GreenNodeFactoryWriter(definition)
                greenFactoryWriter.WriteFactories(output)

                Dim syntaxFactsWriter As New syntaxFactsWriter(definition)
                syntaxFactsWriter.GenerateFile(output)
            End If

            If writeTests Then
                Dim testWriter As New testWriter(definition)
                testWriter.WriteTestCode(output)
            End If

            WriteLine("{0} node structures, {1} enumerations, {2} node kinds", definition.NodeStructures.Count, definition.Enumerations.Count, definition.NodeKinds.Count)
        End Using

    End Sub

End Module
